//---------------------------------------------------------------------------
// CBlockStream Class
// Author : Woo-Hyun Kim
// Email : woorung@nhncorp.com
// Date : Dec. 5, 2007
//---------------------------------------------------------------------------
#include "CBlockStream.h"
//---------------------------------------------------------------------------
CBlockStream::CBlockStream(const char *filename)
{
	use_file_stream = true;

	//buf = new CBufferedStream(filename);
	buf = new CBufferedLineStream(filename);
	block_stream = new istream(buf);

	eol = END_OF_LINE;

	buf->assignblock(0,1);
}
//---------------------------------------------------------------------------
CBlockStream::CBlockStream(stringbuf *strbuf)
{
	use_file_stream = false;

	//buf = (CBufferedStream *) stdbuf;
	buf = (CBufferedLineStream *) strbuf;
	block_stream = new istream(buf);

	eol = END_OF_LINE;
}
//---------------------------------------------------------------------------
CBlockStream::CBlockStream(streambuf *stdbuf)
{
	use_file_stream = false;

	//buf = (CBufferedStream *) stdbuf;
	buf = (CBufferedLineStream *) stdbuf;
	block_stream = new istream(buf);

	eol = END_OF_LINE;
}
//---------------------------------------------------------------------------
CBlockStream::CBlockStream(const CBlockStream &rhs)
{
	// not yet
}
//---------------------------------------------------------------------------
CBlockStream &CBlockStream::operator=(const CBlockStream &rhs) 
{
	// not yet
}
//---------------------------------------------------------------------------
CBlockStream::~CBlockStream()
{
	delete block_stream;
	if(use_file_stream) delete buf;
}
//---------------------------------------------------------------------------
long CBlockStream::assignBlock(long block, long blocks)
{
	if(use_file_stream) return buf->assignblock(block,blocks);
	else {
		cerr << "only filestream can assign blocks" << endl;
	}
}
//---------------------------------------------------------------------------
long CBlockStream::seekg(long pos)
{
	return buf->seekg(pos);
}
//---------------------------------------------------------------------------
long CBlockStream::adjust_seekg(long pos)
{
	long nothing = pos;
	buf->adjusted_line_seekg(pos, nothing);
	return pos;
}
//---------------------------------------------------------------------------
void CBlockStream::clear()
{
	block_stream->clear();
}
//---------------------------------------------------------------------------
long CBlockStream::tellg()
{
	return buf->tellg();
}
//---------------------------------------------------------------------------
long CBlockStream::size()
{
	return buf->size();
}
//---------------------------------------------------------------------------
void CBlockStream::resize(int buf_size)
{
	buf->resize(buf_size);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// there is no key position, since the key can be extracted from vectors
//---------------------------------------------------------------------------
long CBlockStream::getline(vector< vector<string> > &kv_vectors, char delim, long limit)
{
	char c;
	vector<string> kv;
	stringstream item;

	while(!block_stream->eof()) {
		if(!block_stream->get(c).fail()) {
			if(c==delim) {
				// skip delimeter 
				//item << c;

				kv.push_back(item.str());
				item.str("");
			}
			else if(c==eol) {
				// skip eol
				//item << c;

				kv.push_back(item.str());
				item.str("");

				// add
				kv_vectors.push_back(kv);

#ifdef DEBUG
				int key = 1;

				cout << "#key = " << kv[key] << endl;
				cout << "#value = ";
				for(int i=0;i<kv.size();i++) cout << kv[i] << delim;
				cout << endl;
#endif

				if(kv_vectors.size()>=limit) return kv_vectors.size();

				kv.clear();
			}
			else {
				item << c;
			}
		}
		else {
			//cerr << "### huck~! what the heck is get() failure" << endl;
			block_stream->clear();
			block_stream->ignore();
		}
	}

	// if there is the rest of items
	if(kv.size()>0) {
		// skip eol
		//item << eol;

		kv.push_back(item.str());

		kv_vectors.push_back(kv);

#ifdef DEBUG
		int key = 1;

		cout << "#key = " << kv[key] << endl;
		cout << "#value = ";
		for(int i=0;i<kv.size();i++) cout << kv[i] << delim;
		cout << endl;
#endif
	}

	return kv_vectors.size();
}
//---------------------------------------------------------------------------
// there is no key position, that is, the key must be pre-arragned on the 1st position
//---------------------------------------------------------------------------
long CBlockStream::getline(vector< pair<string,string> > &kv_pairs, char delim, long limit)
{
	int pos = 0;

	char line[MAX_BUF_SIZE];
	while(!block_stream->eof()) {
		if(block_stream->fail()) block_stream->clear();

		pair<string,string> kv;
		if(!block_stream->getline(line,MAX_BUF_SIZE,delim).fail()) {
			kv.first = line;

#ifdef DEBUG
			cout << "key = " << line << endl;
#endif

			if(!block_stream->getline(line,MAX_BUF_SIZE,eol).fail()) {
				kv.second = line;

#ifdef DEBUG
				cout << "value = " << line << endl;
#endif
			}
			else  {
				kv.second = "";
#ifdef DEBUG
				cout << endl;
#endif
			}

			kv_pairs.push_back(kv);

			if(kv_pairs.size()>=limit) return kv_pairs.size();
		}
	}

	return kv_pairs.size();
}
//---------------------------------------------------------------------------
long CBlockStream::getline(vector< pair<string,string> > &kv_pairs, char delim, int kpos, long limit)
{
	stringstream key;
	stringstream value;

	int pos = 0;

	char line[MAX_BUF_SIZE];
	for(long limit=0;!block_stream->eof();) {
		if(block_stream->fail()) block_stream->clear();

		if(!block_stream->getline(line,MAX_BUF_SIZE,delim).fail()) {
			value << line << delim;

			if(++pos>=kpos) {
				key << line;
				if(!block_stream->getline(line,MAX_BUF_SIZE, '\n').fail()) value << line;

				// add (k,v) pair
				pair<string,string> kv;
				kv.first = key.str();
				kv.second = value.str();
				kv_pairs.push_back(kv);

				if(++limit>=limit) return limit;

				// initialize
				pos = 0;
				key.str("");
				value.str("");
			}
		}
	}

	if(kv_pairs.size()>0) return kv_pairs.size();
	else return EOF;
}
//---------------------------------------------------------------------------
long CBlockStream::getline(char *line, size_t size)
{
	char delim = ' ';

	return getline(line, size, delim);
}
//---------------------------------------------------------------------------
long CBlockStream::getline(char *line, size_t size, char delim)
{
	if(!block_stream->eof()) {
		if(block_stream->getline(line, size, delim).fail()) block_stream->clear();

		return strlen(line);
	}
	else {
		line[0] = '\0';
		return EOF;
	}
}
//---------------------------------------------------------------------------
long CBlockStream::getline(char *line, size_t size, char *delim)
{
	char c;
	int len = strlen(delim);

	int i=0, j=0;
	for(i=0,j=0;i<size-1&&!block_stream->eof();i++) {
		if(!block_stream->get(c).fail()) {
			for(j=0;j<len;j++) {
				if(c==delim[j]) {
					line[i] = '\0';

					return strlen(line);
				}
				else continue;
			}
			line[i] = c;
		}
		else {
			line[i] = '\0';
			return strlen(line);
		}
	}

	line[i] = '\0';
	if(i==0&&block_stream->eof()) return EOF;
	else return strlen(line);
}
//---------------------------------------------------------------------------
